/*
 * Copyright 2011 The Rusted Roof, LLC.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

package org.proteusframework.platformservice.persistence.base;

import org.proteusframework.core.api.model.INamespace;
import org.proteusframework.core.base.DisplayableName;
import org.proteusframework.core.util.Assert;
import org.proteusframework.platformservice.AbstractServicePlugin;
import org.proteusframework.platformservice.IExtendedPlatformDelegate;
import org.proteusframework.platformservice.grammar.IGrammarInspector;
import org.proteusframework.platformservice.grammar.IGrammarInspectorFactory;
import org.proteusframework.platformservice.grammar.IllegalExpressionException;
import org.proteusframework.platformservice.persistence.api.*;
import org.proteusframework.platformservice.persistence.api.messagebean.IMessageBeanDescriptor;
import org.proteusframework.platformservice.persistence.api.messagebean.IMessageBeanDescriptorVisitor;
import org.proteusframework.platformservice.persistence.api.messagebean.IMessageBeanProperty;
import org.proteusframework.platformservice.persistence.messagebean.DataType;
import org.proteusframework.platformservice.persistence.messagebean.NullMessageBeanManager;
import org.proteusframework.platformservice.persistence.messagebean.UnsupportedMessageBeanException;
import org.proteusframework.platformservice.persistence.project.NoSuchProjectException;
import org.proteusframework.platformservice.persistence.project.NullProjectManager;
import org.proteusframework.platformservice.persistence.project.ProjectInitializationException;
import org.proteusframework.platformservice.persistence.vfs.FilePath;
import org.proteusframework.platformservice.persistence.vfs.NullVFSManager;

import java.beans.PropertyChangeListener;
import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.SortedSet;

/**
 * Base class for all <code>IPersistenceService</code> implementations.
 *
 * @author Tacoma Four
 */
public abstract class AbstractPersistenceService extends AbstractServicePlugin implements IPersistenceService
{
    private final boolean primordialFlag;

    private IMessageBeanManager messageBeanManager;
    private IVFSManager vfsManager;
    private IProjectManager projectManager;
    private IPackageManager packageManager;

    protected AbstractPersistenceService(INamespace namespace, boolean primordialFlag)
    {
        super(new DisplayableName(namespace), AbstractPersistenceService.class);
        this.primordialFlag = primordialFlag;
    }

    protected void injectProjectManager(IProjectManager projectManager)
    {
        Assert.parameterNotNull(projectManager, "Parameter 'projectManager' must not be null");
        this.projectManager = projectManager;
        this.projectManager.setPlatformDelegate(delegate, IExtendedPlatformDelegate.class);
    }

    protected void injectVFSManager(IVFSManager vfsManager)
    {
        Assert.parameterNotNull(vfsManager, "Parameter 'vfsManager' must not be null");
        this.vfsManager = vfsManager;
        this.vfsManager.setPlatformDelegate(delegate, IExtendedPlatformDelegate.class);
    }

    protected void injectMessageBeanManager(IMessageBeanManager registrar)
    {
        Assert.parameterNotNull(registrar, "Parameter 'messageBeanManager' must not be null");
        this.messageBeanManager = registrar;
        this.messageBeanManager.setPlatformDelegate(delegate, IExtendedPlatformDelegate.class);
    }

    protected void injectPackageManager(IPackageManager packageManager)
    {
        Assert.parameterNotNull(packageManager, "Parameter 'packageManager' must not be null");
        this.packageManager = packageManager;
        this.packageManager.setPlatformDelegate(delegate, IExtendedPlatformDelegate.class);
    }

    @Override
    public final boolean isPrimordial()
    {
        return primordialFlag;
    }

    @Override
    public final boolean supportsProjectManagement()
    {
        return (null != projectManager && !(projectManager instanceof NullProjectManager));
    }

    @Override
    public final void removePropertyChangeListener(PropertyChangeListener projectPropertiesListener)
    {
        projectManager.removePropertyChangeListener(projectPropertiesListener);
    }

    @Override
    public final void addPropertyChangeListener(PropertyChangeListener projectPropertiesListener)
    {
        projectManager.addPropertyChangeListener(projectPropertiesListener);
    }

    @Override
    public final void setCurrentProjectDescription(String description)
    {
        projectManager.setCurrentProjectDescription(description);
    }

    @Override
    public final void setCurrentProjectProperty(String propertyGroup, String key, String value)
    {
        projectManager.setCurrentProjectProperty(propertyGroup, key, value);
    }

    @Override
    public final void create(IProjectDescriptor descriptor) throws ProjectInitializationException
    {
        projectManager.create(descriptor);
    }

    @Override
    public final void open(IProjectDescriptor descriptor) throws NoSuchProjectException, ProjectInitializationException
    {
        projectManager.open(descriptor);
    }

    @Override
    public final void delete(IProjectDescriptor descriptor) throws NoSuchProjectException
    {
        projectManager.delete(descriptor);
    }

    @Override
    public void accept(IProjectManagerVisitor visitor) throws IOException
    {
        projectManager.accept(visitor);
    }

    @Override
    public final IProjectDescriptor getCurrentProject()
    {
        return projectManager.getCurrentProject();
    }

    @Override
    public final boolean isProjectOpen()
    {
        return projectManager.isProjectOpen();
    }

    @Override
    public final void save()
    {
        projectManager.save();
    }

    @Override
    public final void saveAs(IProjectDescriptor descriptor) throws ProjectInitializationException
    {
        projectManager.saveAs(descriptor);
    }

    @Override
    public final void close()
    {
        projectManager.close();
    }

    @Override
    public final List<IProjectDescriptor> listProjects()
    {
        return projectManager.listProjects();
    }

    @Override
    public final IProjectDescriptor getLastOpenedProject() throws NoSuchProjectException
    {
        return projectManager.getLastOpenedProject();
    }

    @Override
    public final void clearLastOpenedProjectPath()
    {
        projectManager.clearLastOpenedProjectPath();
    }

    @Override
    public final boolean doesProjectExist(INamespace namespace)
    {
        return projectManager.doesProjectExist(namespace);
    }

    @Override
    public final IProjectDescriptor loadProjectDescriptor(INamespace namespace) throws NoSuchProjectException
    {
        return projectManager.loadProjectDescriptor(namespace);
    }

    @Override
    public final boolean isValidProjectName(String projectName)
    {
        return projectManager.isValidProjectName(projectName);
    }

    @Override
    public boolean supportsPackageManagement()
    {
        return packageManager.supportsPackageManagement();
    }

    @Override
    public void acceptPackageVisitor(IPackagingVisitor visitor, File packageFile) throws IOException
    {
        packageManager.acceptPackageVisitor(visitor, packageFile);
    }

    @Override
    public final boolean supportsVFSManagement()
    {
        return (null != vfsManager && !(vfsManager instanceof NullVFSManager));
    }

    @Override
    public final boolean hasFile(FilePath filePath)
    {
        return vfsManager.hasFile(filePath);
    }

    @Override
    public final List<IVFSFile> getFiles(FilePath filePath)
    {
        return vfsManager.getFiles(filePath);
    }

    @Override
    public final IVFSFile getFile(FilePath filePath)
    {
        return vfsManager.getFile(filePath);
    }

    @Override
    public final IVFSFile createFile(FilePath filePath)
    {
        return vfsManager.createFile(filePath);
    }

    @Override
    public final boolean deleteFile(IVFSFile vfsFile)
    {
        return vfsManager.deleteFile(vfsFile);
    }

    @Override
    public final boolean deleteFile(FilePath filePath)
    {
        return vfsManager.deleteFile(filePath);
    }

    @Override
    public void accept(IVFSVisitor visitor) throws IOException
    {
        vfsManager.accept(visitor);
    }

    @Override
    public final boolean supportsMessageBeanManagement()
    {
        return (null != messageBeanManager && !(messageBeanManager instanceof NullMessageBeanManager));
    }

    @Override
    public final void setGrammarInspectorFactory(IGrammarInspectorFactory factory)
    {
        messageBeanManager.setGrammarInspectorFactory(factory);
    }

    @Override
    public IGrammarInspector createGrammarInspector(IMessageBeanDescriptor messageBeanDescriptor)
    {
        return messageBeanManager.createGrammarInspector(messageBeanDescriptor);
    }

    @Override
    public final boolean supportsExpressionQueries()
    {
        return messageBeanManager.supportsExpressionQueries();
    }

    @Override
    public final boolean supportsInterfaces()
    {
        return messageBeanManager.supportsInterfaces();
    }

    @Override
    public void accept(IMessageBeanDescriptorVisitor visitor) throws IOException
    {
        messageBeanManager.accept(visitor);
    }

    @Override
    public final boolean supportsIndices()
    {
        return messageBeanManager.supportsIndices();
    }

    @Override
    public final List<String> describeExpressionSupport()
    {
        return messageBeanManager.describeExpressionSupport();
    }

    @Override
    public final boolean isMessageBeanRegistered(IMessageBeanDescriptor messageBeanDescriptor)
    {
        return messageBeanManager.isMessageBeanRegistered(messageBeanDescriptor);
    }

    @Override
    public final SortedSet<IMessageBeanDescriptor> getMessageBeanDescriptors()
    {
        return messageBeanManager.getMessageBeanDescriptors();
    }

    @Override
    public final void queueMessageBeanRegistration(IMessageBeanDescriptor messageBeanDescriptor) throws UnsupportedMessageBeanException
    {
        messageBeanManager.queueMessageBeanRegistration(messageBeanDescriptor);
    }

    @Override
    public void processRegistrationQueue()
    {
        messageBeanManager.processRegistrationQueue();
    }

    @Override
    public final boolean isMessageBeanRegistered(INamespace namespace)
    {
        return messageBeanManager.isMessageBeanRegistered(namespace);
    }

    @Override
    public final IMessageBeanDescriptor getMessageBeanDescriptor(INamespace namespace)
    {
        return messageBeanManager.getMessageBeanDescriptor(namespace);
    }

    @Override
    public final <T> long saveMessage(Class<T> messageBeanClass, T message)
    {
        return messageBeanManager.saveMessage(messageBeanClass, message);
    }

    @Override
    public final <T> boolean deleteMessage(Class<T> messageBeanClass, T message)
    {
        return messageBeanManager.deleteMessage(messageBeanClass, message);
    }

    @Override
    public final boolean supportsDeletes()
    {
        return messageBeanManager.supportsDeletes();
    }

    @Override
    public final boolean supportsUpdates()
    {
        return messageBeanManager.supportsUpdates();
    }

    @Override
    public final <T> boolean updateMessage(Class<T> messageBeanClass, T message, IMessageBeanProperty[] properties)
    {
        return messageBeanManager.updateMessage(messageBeanClass, message, properties);
    }

    @Override
    public final <T> List<T> listMessages(Class<T> messageBeanClass)
    {
        return messageBeanManager.listMessages(messageBeanClass);
    }

    @Override
    public final <T> Iterable<T> createIterator(Class<T> messageBeanClass)
    {
        return messageBeanManager.createIterator(messageBeanClass);
    }

    @Override
    public final <T> IResultSet<T> executeQuery(Class<T> messageBeanClass, String query) throws org.proteusframework.platformservice.grammar.IllegalExpressionException
    {
        return messageBeanManager.executeQuery(messageBeanClass, query);
    }

    @Override
    public final boolean supportsParameterizedQueries()
    {
        return messageBeanManager.supportsParameterizedQueries();
    }

    @Override
    public final <T> IResultSet<T> executeQuery(Class<T> messageBeanClass, String query, Object... params) throws IllegalExpressionException
    {
        return messageBeanManager.executeQuery(messageBeanClass, query, params);
    }

    @Override
    public final List<DataType> describeDataTypeSupport()
    {
        return messageBeanManager.describeDataTypeSupport();
    }

    @Override
    public final <T> T narrow(Class<T> managerInterface) throws IllegalArgumentException
    {
        if (supportsProjectManagement() && managerInterface.equals(IProjectManager.class))
        {
            return managerInterface.cast(this);
        } else if (supportsMessageBeanManagement() && managerInterface.equals(IMessageBeanManager.class))
        {
            return managerInterface.cast(this);
        } else if (supportsPackageManagement() && managerInterface.equals(IPackageManager.class))
        {
            return managerInterface.cast(this);
        } else if (supportsVFSManagement() && managerInterface.equals(IVFSManager.class))
        {
            return managerInterface.cast(this);
        } else if (supportsMessageBeanManagement() && this.messageBeanManager.getClass().equals(managerInterface))
        {
            return managerInterface.cast(this.messageBeanManager);
        } else if (supportsVFSManagement() && this.vfsManager.getClass().equals(managerInterface))
        {
            return managerInterface.cast(this.vfsManager);
        } else if (supportsProjectManagement() && this.projectManager.getClass().equals(managerInterface))
        {
            return managerInterface.cast(this.projectManager);
        } else
        {
            throw new IllegalArgumentException("IPersistenceService cannot be narrowed to this interface (" + managerInterface.getCanonicalName() + ")");
        }
    }
}
